﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using KongMing.Project.Entity.Business;
using KongMing.Project.Entity.Enum;
using System.Reflection;

namespace KongMing.Project.Common
{
    /// <summary>
    /// 通用表达式帮助类
    /// </summary>
    public static class ExpressionHelper
    {
        #region 表达式公共方法

        /// <summary>
        /// 【true】：p=>true
        /// </summary>
        public static Expression<Func<T, bool>> True<T>()
        {
            return p => true;
        }

        /// <summary>
        /// 【false】：p=>false
        /// </summary>
        public static Expression<Func<T, bool>> False<T>()
        {
            return p => false;
        }

        /// <summary>
        /// 【属性名】：p=>p.propertyName
        /// </summary>
        public static Expression<Func<T, TKey>> GetOrderExpression<T, TKey>(string propertyName)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
            return Expression.Lambda<Func<T, TKey>>(Expression.Property(parameter, propertyName), parameter);
        }



        /// <summary>
        /// 【and】连接两个表达式 
        /// </summary>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            //声明传递参数（也就是上面表达式树里面的参数s）
            ParameterExpression p = Expression.Parameter(typeof(T), "p");
            //统一管理参数，保证参数一致，否则会报错 变量未定义
            MyExpressionVisitor visitor = new MyExpressionVisitor(p);
            //表达式树内容
            Expression body1 = visitor.Visit(expr1.Body);
            Expression body2 = visitor.Visit(expr2.Body);
            //合并表达式
            return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(body1, body2), p);
        }

        /// <summary>
        /// 【or】连接两个表达式
        /// </summary>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            //声明传递参数（也就是上面表达式树里面的参数s）
            ParameterExpression p = Expression.Parameter(typeof(T), "p");
            //统一管理参数，保证参数一致，否则会报错 变量未定义
            MyExpressionVisitor visitor = new MyExpressionVisitor(p);
            //表达式树内容
            Expression body1 = visitor.Visit(expr1.Body);
            Expression body2 = visitor.Visit(expr2.Body);
            //合并表达式
            return Expression.Lambda<Func<T, bool>>(Expression.OrElse(body1, body2), p);
        }

        #endregion

        #region 创建条件表达式，指定泛型参数

        /// <summary>
        /// 【in】/【not in】
        /// </summary>
        public static Expression<Func<T, bool>> GetWhere_InorNotIn_Exp<T>(string field, object value, string valueType, bool ifIn = true)
        {
            Expression<Func<T, bool>> whereExp = True<T>();
            List<string> values = value.ToString().Split(new char[] { ',', '，', '|' }).ToList();
            if (ifIn)
            {
                Expression<Func<T, bool>> orExp = False<T>();
                foreach (var val in values)
                    orExp = orExp.Or<T>(CreateEqual<T>(field, val, valueType));
                whereExp = whereExp.And(orExp);
            }
            else
            {
                foreach (var val in values)
                    whereExp = whereExp.And<T>(CreateNotEqual<T>(field, val, valueType));
            }
            return whereExp;
        }

        /// <summary>
        /// 【等于】：p=>p.propertyName == propertyValue
        /// 泛型参数
        /// </summary>
        public static Expression<Func<T, bool>> CreateEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(S));//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
        }

        /// <summary>
        /// 【不等于】：p=>p.propertyName != propertyValue
        ///  泛型参数
        /// </summary>
        public static Expression<Func<T, bool>> CreateNotEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(S));//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter);
        }

        /// <summary>
        /// 【大于】：p=>p.propertyName > propertyValue
        ///  泛型参数
        /// </summary>
        public static Expression<Func<T, bool>> CreateGreaterThan<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(S));//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter);
        }

        /// <summary>
        /// 【小于】：p=>  propertyValue ＜ p.propertyName 
        ///  泛型参数
        /// </summary>
        public static Expression<Func<T, bool>> CreateLessThan<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(S));//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter);
        }

        /// <summary>
        /// 【大于等于】：p=>p.propertyName >= propertyValue
        ///  泛型参数
        /// </summary>
        public static Expression<Func<T, bool>> CreateGreaterThanOrEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(S));//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter);
        }

        /// <summary>
        /// 【小于等于】：p=>propertyValue ＜= p.propertyName 
        ///  泛型参数
        /// </summary>
        public static Expression<Func<T, bool>> CreateLessThanOrEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(S));//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter);
        }

        /// <summary>
        /// 【模糊匹配】：p=>p.propertyName.Contains(propertyValue)
        /// </summary>
        public static Expression<Func<T, bool>> CreateContains<T>(string propertyName, string propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            ConstantExpression constant = Expression.Constant(propertyValue, typeof(string));
            return Expression.Lambda<Func<T, bool>>(Expression.Call(member, method, constant), parameter);
        }

        #endregion

        #region 创建条件表达式，未知参数类型
        /// <summary>
        /// 【等于】：p=>p.propertyName == propertyValue
        /// 未知参数类型
        /// </summary>
        public static Expression<Func<T, bool>> CreateEqual<T>(string propertyName, object propertyValue, string valueType)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = CreateValueConstant(propertyValue, valueType);//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
        }

        /// <summary>
        /// 【不等于】：p=>p.propertyName != propertyValue
        ///  未知参数类型
        /// </summary>
        public static Expression<Func<T, bool>> CreateNotEqual<T>(string propertyName, object propertyValue, string valueType)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = CreateValueConstant(propertyValue, valueType);//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter);
        }

        /// <summary>
        /// 【大于】：p=>p.propertyName > propertyValue
        ///  未知参数类型
        /// </summary>
        public static Expression<Func<T, bool>> CreateGreaterThan<T>(string propertyName, object propertyValue, string valueType)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = CreateValueConstant(propertyValue, valueType);//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter);
        }

        /// <summary>
        /// 【小于】：p=>  propertyValue ＜ p.propertyName 
        ///  未知参数类型
        /// </summary>
        public static Expression<Func<T, bool>> CreateLessThan<T>(string propertyName, object propertyValue, string valueType)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = CreateValueConstant(propertyValue, valueType);//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter);
        }

        /// <summary>
        /// 【大于等于】：p=>p.propertyName >= propertyValue
        ///  未知参数类型
        /// </summary>
        public static Expression<Func<T, bool>> CreateGreaterThanOrEqual<T>(string propertyName, object propertyValue, string valueType)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = CreateValueConstant(propertyValue, valueType);//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter);
        }

        /// <summary>
        /// 【小于等于】：p=>propertyValue ＜= p.propertyName 
        ///  未知参数类型
        /// </summary>
        public static Expression<Func<T, bool>> CreateLessThanOrEqual<T>(string propertyName, object propertyValue, string valueType)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");//创建参数p
            MemberExpression member = Expression.PropertyOrField(parameter, propertyName);
            ConstantExpression constant = CreateValueConstant(propertyValue, valueType);//创建常数
            return Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter);
        }



        #endregion

        #region 未知参数类型,判断参数类型创建参数

        /// <summary>
        /// 获取参数的实际类型
        /// </summary>
        private static ConstantExpression CreateValueConstant(object value, string valueType)
        {

            ConstantExpression constant = Expression.Constant(value, typeof(object));
            constant = valueType switch
            {
                "string" => Expression.Constant(LibConvert.ObjToStr(value), typeof(string)),
                "int" => Expression.Constant(LibConvert.ObjToInt(value), typeof(int)),
                "double" => Expression.Constant(LibConvert.ObjToDouble(value), typeof(double)),
                "bool" => Expression.Constant(LibConvert.ObjToBool(value), typeof(bool)),
                "datetime" => Expression.Constant(LibConvert.ObjToDateTime(value), typeof(DateTime)),
                _ => throw new Exception("valueType(值类型)不合法！")
            };
            return constant;
        }

        #endregion


        public class MyExpressionVisitor : ExpressionVisitor
        {
            public ParameterExpression _Parameter { get; set; }

            public MyExpressionVisitor(ParameterExpression Parameter)
            {
                _Parameter = Parameter;
            }
            protected override Expression VisitParameter(ParameterExpression p)
            {
                return _Parameter;
            }

            public override Expression Visit(Expression node)
            {
                return base.Visit(node);//Visit会根据VisitParameter()方法返回的Expression修改这里的node变量
            }
        }

    }
}
